﻿namespace Microsoft.VisualStudio.IDE.ToolboxControlsInstaller
{
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.OLE.Interop;
    using Microsoft.VisualStudio.Shell;
    using Microsoft.VisualStudio.Shell.Interop;
    using Microsoft.Win32;
    using Microsoft.Windows.Design;
    using Microsoft.Windows.Design.Host;
    using Microsoft.Windows.Design.Interaction;
    using Microsoft.Windows.Design.Metadata;
    using Microsoft.Windows.Design.Metadata.Reflection;
    using MS.Internal.Package;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Runtime.Versioning;
    using System.Windows;
    using System.Windows.Forms;

    internal abstract class XamlAssembly : RegisteredAssembly
    {
        private static IsolationProvider _lastIsolationProvider;
        private static FrameworkName _lastTargetFrameworkName;
        private const string TabProperty = "VSTOOLBOXTAB";

        public XamlAssembly(AssemblyName assemblyName) : base(assemblyName)
        {
        }

        public override bool AddItemsToToolbox(IServiceProvider provider, RegistryKey applicationRegistryRoot)
        {
            bool flag = false;
            IVsActivityLog service = provider.GetService(typeof(SVsActivityLog)) as IVsActivityLog;
            service.LogEntry(3, this.ToString(), "Toolbox Controls Installer Package attempting to add Toolbox items");
            service.LogEntry(3, this.ToString(), string.Format(CultureInfo.CurrentCulture, "Attempting to get Toolbox items from Assembly {0}", new object[] { base.AssemblyName.FullName }));
            provider.GetService(typeof(SVsFrameworkMultiTargeting));
            IQueryToolboxItems items = (IQueryToolboxItems) this.GetIsolationProvider(provider).CreateRemoteInstance(typeof(IsolationProxy));
            ICollection is2 = null;
            try
            {
                is2 = items.GetToolboxItems(base.AssemblyName, this.FrameworkElementAssemblySpec, new ArrayList(this.ExclusionList.ToArray()));
            }
            catch (Exception exception)
            {
                service.LogEntry(1, this.ToString(), string.Format(CultureInfo.CurrentCulture, "Assembly {0} threw exception {1} when attempting to enumerate Types.", new object[] { base.AssemblyName.FullName, exception.ToString() }));
            }
            if ((is2 == null) || (is2.Count == 0))
            {
                service.LogEntry(2, this.ToString(), string.Format(CultureInfo.CurrentCulture, "Assembly {0} did not contain any WPF/SL toolbox items.", new object[] { base.AssemblyName.FullName }));
                return flag;
            }
            foreach (IDictionary dictionary in is2)
            {
                string typeName = dictionary["CreationTypeName"].ToString();
                string fullTypeName = base.ExtractFullTypeName(typeName);
                string str3 = base.ExtractShortTypeName(typeName);
                service.LogEntry(3, this.ToString(), string.Format(CultureInfo.CurrentCulture, "Attempting to add Toolbox item {0}", new object[] { fullTypeName }));
                string tabName = null;
                if (dictionary.Contains("VSTOOLBOXTAB"))
                {
                    tabName = (string) dictionary["VSTOOLBOXTAB"];
                    dictionary.Remove("VSTOOLBOXTAB");
                }
                byte[] buffer = ToolEncoder.Encode(dictionary);
                OleDataObject dataObj = new OleDataObject();
                dataObj.SetData(DataFormats.GetDataFormat(this.ClipFormat).Name, false, new MemoryStream(buffer));
                TBXITEMINFO itemInfo = new TBXITEMINFO();
                TBXITEMINFO itemInfoAll = new TBXITEMINFO();
                itemInfo.bstrText = str3;
                byte[] buffer2 = (byte[]) dictionary["Bitmap"];
                Bitmap bitmap = null;
                Color black = Color.Black;
                if (buffer2 != null)
                {
                    bitmap = new Bitmap(new MemoryStream(buffer2));
                }
                else
                {
                    bitmap = new Bitmap(typeof(XamlAssembly).Assembly.GetManifestResourceStream(typeof(XamlAssembly), "DefaultBitmap.bmp"));
                }
                itemInfoAll = itemInfo;
                if (bitmap != null)
                {
                    if ((bitmap.Height > 0) && (bitmap.Width > 0))
                    {
                        black = bitmap.GetPixel(0, bitmap.Size.Height - 1);
                    }
                    if (black.A < 0xff)
                    {
                        black = Color.FromArgb(0xff, black);
                    }
                    itemInfo.hBmp = ControlPaint.CreateHBitmap16Bit(bitmap, black);
                    itemInfo.clrTransparent = (uint) ColorTranslator.ToWin32(black);
                    itemInfo.dwFlags = 1;
                    itemInfoAll.hBmp = ControlPaint.CreateHBitmap16Bit(bitmap, black);
                    itemInfoAll.clrTransparent = (uint) ColorTranslator.ToWin32(black);
                    itemInfoAll.dwFlags = 1;
                }
                if (this.AddToToolbox(provider, tabName, this.CreateControl(fullTypeName, dictionary), dataObj, itemInfo, itemInfoAll))
                {
                    flag = true;
                }
            }
            return flag;
        }

        private bool AddToToolbox(IServiceProvider provider, string tabName, DictionaryControl control, IDataObject dataObj, TBXITEMINFO itemInfo, TBXITEMINFO itemInfoAll)
        {
            if (dataObj is IDataObject)
            {
                dataObj = new SettableOleDataObject(dataObj as IDataObject);
            }
            provider.GetService(typeof(SVsActivityLog));
            string typeName = control.Properties["CreationTypeName"].ToString();
            string szValue = base.ExtractFullTypeName(typeName);
            base.ExtractShortTypeName(typeName);
            if (!string.IsNullOrEmpty(base.TargetFramework))
            {
                IVsStringMap map;
                IVsDataObjectStringMapManager manager = provider.GetService(typeof(SVsDataObjectStringMapManager)) as IVsDataObjectStringMapManager;
                manager.CreateStringMap(out map);
                map.SetValue("TypeName", szValue);
                map.SetValue("AssemblyName", base.AssemblyName.FullName);
                map.SetValue("Frameworks", base.TargetFramework);
                map.SetValue("ItemProvider", "{" + base.GetType().GUID.ToString() + "}");
                manager.WriteStringMap(dataObj, "MultiTargeting:{FBB22D27-7B21-42ac-88C8-595F94BDBCA5}", 1, map);
            }
            object service = provider.GetService(typeof(SVsToolbox));
            IVsToolbox2 toolbox = service as IVsToolbox2;
            IVsToolbox3 toolbox2 = service as IVsToolbox3;
            if (string.IsNullOrEmpty(tabName))
            {
                if (base.ToolboxItemCategories.ContainsKey(szValue))
                {
                    tabName = base.ToolboxItemCategories[szValue];
                }
                else
                {
                    tabName = base.DefaultCategory;
                }
            }
            int hr = 0;
            if (!string.IsNullOrEmpty(tabName))
            {
                if ((string.CompareOrdinal(tabName, "Common") == 0) && !ErrorHandler.Succeeded(toolbox2.GetTabOfID(this.InvariantCommonCategory, out tabName)))
                {
                    tabName = null;
                }
                if (!string.IsNullOrEmpty(tabName))
                {
                    TBXITEMINFO[] ptif = new TBXITEMINFO[] { itemInfo };
                    hr = toolbox.AddItem(dataObj, ptif, tabName);
                }
            }
            if (!string.IsNullOrEmpty(this.InvariantAllItemsCategory))
            {
                if (!ErrorHandler.Succeeded(toolbox2.GetTabOfID(this.InvariantAllItemsCategory, out tabName)))
                {
                    tabName = null;
                }
                if (!string.IsNullOrEmpty(tabName))
                {
                    TBXITEMINFO[] tbxiteminfoArray2 = new TBXITEMINFO[] { itemInfoAll };
                    hr = toolbox.AddItem(dataObj, tbxiteminfoArray2, tabName);
                }
            }
            if (ErrorHandler.Succeeded(hr))
            {
                base.RegisteredControls.Add(control);
                return true;
            }
            return false;
        }

        protected abstract DictionaryControl CreateControl(string fullTypeName, IDictionary toolProperties);
        private IsolationProvider GetIsolationProvider(IServiceProvider provider)
        {
            FrameworkName targetFramework = new FrameworkName(this.GetTargetIsolationFramework());
            if ((targetFramework != _lastTargetFrameworkName) || (_lastIsolationProvider == null))
            {
                IsolationProviderService service = provider.GetService(typeof(IsolationProviderService)) as IsolationProviderService;
                if (service == null)
                {
                    throw new InvalidOperationException();
                }
                UnloadAppDomain();
                _lastIsolationProvider = service.CreateGlobalIsolationProvider(targetFramework);
                _lastTargetFrameworkName = targetFramework;
            }
            return _lastIsolationProvider;
        }

        private string GetTargetIsolationFramework()
        {
            return (base.TargetFramework ?? this.DefaultFramework);
        }

        public static void UnloadAppDomain()
        {
            if (_lastIsolationProvider != null)
            {
                _lastIsolationProvider.Dispose();
                _lastIsolationProvider = null;
            }
            _lastTargetFrameworkName = null;
        }

        protected abstract int ClipFormat { get; }

        protected abstract string DefaultFramework { get; }

        protected abstract List<string> ExclusionList { get; }

        protected abstract AssemblyName FrameworkElementAssemblySpec { get; }

        protected abstract string InvariantAllItemsCategory { get; }

        protected abstract string InvariantCommonCategory { get; }

        [ComVisible(true)]
        private class IsolationProxy : ICustomQueryInterface, IQueryToolboxItems
        {
            private IModifiableMetadataContext _metadataContext = (AppDomain.CurrentDomain.GetData(typeof(IMetadataContext).FullName) as IModifiableMetadataContext);
            private static Guid IID_IManagedObject = new Guid("{C3FCC19E-A970-11D2-8B5A-00A0C9B7C9C4}");

            internal CreationTool GetCreationTool(ITypeMetadata controlTypeMeta)
            {
                ITypeMetadata attributeType = this._metadataContext.GetType(typeof(CreationToolAttribute));
                Type runtimeType = controlTypeMeta.GetRuntimeType();
                CreationTool tool = null;
                foreach (IAttributeMetadata metadata2 in controlTypeMeta.GetAttributes(attributeType))
                {
                    CreationToolAttribute attribute = (CreationToolAttribute) metadata2.GetValue();
                    if (attribute.get_ToolType() != null)
                    {
                        tool = Activator.CreateInstance(attribute.get_ToolType()) as CreationTool;
                    }
                    if (tool != null)
                    {
                        tool.set_CreationType(runtimeType);
                    }
                    return tool;
                }
                return tool;
            }

            public CustomQueryInterfaceResult GetInterface(ref Guid iid, out IntPtr ppv)
            {
                ppv = IntPtr.Zero;
                if (iid.Equals(IID_IManagedObject))
                {
                    return CustomQueryInterfaceResult.Failed;
                }
                return CustomQueryInterfaceResult.NotHandled;
            }

            public ICollection GetToolboxItems(AssemblyName assemblyName, AssemblyName feElementAssemblySpec, IList exclusionList)
            {
                if (this._metadataContext == null)
                {
                    return null;
                }
                ArrayList list = new ArrayList();
                try
                {
                    this._metadataContext.AssemblyNames.Add(assemblyName);
                    IAssemblyMetadata assembly = this._metadataContext.GetAssembly(assemblyName.FullName);
                    if (assembly == null)
                    {
                        return list;
                    }
                    IAssemblyMetadata metadata2 = null;
                    foreach (IAssemblyMetadata metadata3 in this._metadataContext.Assemblies)
                    {
                        if (metadata3.Name.Equals(feElementAssemblySpec.Name, StringComparison.Ordinal))
                        {
                            metadata2 = metadata3;
                            break;
                        }
                    }
                    if (metadata2 == null)
                    {
                        return null;
                    }
                    ITypeMetadata type = metadata2.GetType(typeof(FrameworkElement).FullName);
                    if (type == null)
                    {
                        return null;
                    }
                    foreach (ITypeMetadata metadata5 in assembly.Types)
                    {
                        if (((!exclusionList.Contains(metadata5.FullName) && type.IsAssignableFrom(metadata5)) && (!metadata5.IsAbstract && metadata5.IsVisible)) && !this.HiddenFromToolbox(metadata5))
                        {
                            CreationTool creationTool = this.GetCreationTool(metadata5);
                            if (creationTool != null)
                            {
                                IDictionary toolProperties = ToolEncoder.GetToolProperties(creationTool);
                                toolProperties.Add("VSTOOLBOXTAB", this.GetToolboxTab(metadata5));
                                list.Add(toolProperties);
                            }
                        }
                    }
                }
                catch (Exception exception)
                {
                    ReflectionTypeLoadException exception2 = exception as ReflectionTypeLoadException;
                    if (exception2 != null)
                    {
                        throw new ReflectionTypeLoadException(null, exception2.LoaderExceptions, exception2.Message);
                    }
                    throw;
                }
                return list;
            }

            internal string GetToolboxTab(ITypeMetadata controlTypeMeta)
            {
                ITypeMetadata type = this._metadataContext.GetType(typeof(ToolboxTabNameAttribute));
                foreach (IAttributeMetadata metadata2 in controlTypeMeta.GetAttributes(type))
                {
                    ToolboxTabNameAttribute attribute = (ToolboxTabNameAttribute) metadata2.GetValue();
                    return attribute.get_TabName();
                }
                return null;
            }

            internal bool HiddenFromToolbox(ITypeMetadata controlTypeMeta)
            {
                ITypeMetadata type = this._metadataContext.GetType(typeof(ToolboxBrowsableAttribute));
                foreach (IAttributeMetadata metadata2 in controlTypeMeta.GetAttributes(type))
                {
                    ToolboxBrowsableAttribute attribute = (ToolboxBrowsableAttribute) metadata2.GetValue();
                    return !attribute.get_Browsable();
                }
                return false;
            }
        }
    }
}

